/**
 * Copyright © 2013 Creativor Studio.
 * About license information, please see LICENSE.txt.
 */
package org.creativor.rayson.serialize;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.Array;

/**
 * @author creativor
 * 
 */
final class EnumType extends SerializableType<Enum<?>> {

	/**
	 * @param type
	 */
	protected EnumType(final byte type) {
		super(type);
	}

	@Override
	public Enum<?> read(final DataInput dis) throws SerializeFormatException, IOException {
		String enumClsName, enumName;
		short length;
		byte[] data;
		length = dis.readShort();
		data = new byte[length];
		dis.readFully(data);
		enumClsName = new String(data);
		length = dis.readShort();
		data = new byte[length];
		dis.readFully(data);
		enumName = new String(data);
		try {
			final Class enumType = Class.forName(enumClsName);
			return Enum.valueOf(enumType, enumName);
		} catch (final Exception e) {
			throw new SerializeFormatException("Can not load enum {class:" + enumClsName
					+ ", name:" + enumName + "}", e);
		}
	}

	@Override
	Object readArray(final DataInput dis, final int arrayLength) throws SerializeFormatException,
			IOException {
		String enumClsName, enumName;
		short length;
		byte[] data;
		length = dis.readShort();
		data = new byte[length];
		dis.readFully(data);
		enumClsName = new String(data);
		Class enumType;
		try {
			enumType = Class.forName(enumClsName);
		} catch (final ClassNotFoundException e) {
			throw new SerializeFormatException("Can not find enum class: " + enumClsName, e);
		}

		final Object array = Array.newInstance(enumType, arrayLength);
		for (int i = 0; i < arrayLength; i++) {
			length = dis.readShort();
			data = new byte[length];
			dis.readFully(data);
			enumName = new String(data);
			Array.set(array, i, Enum.valueOf(enumType, enumName));
		}

		return array;
	}

	@Override
	public void write(final DataOutput dos, final Enum<?> value) throws IOException {
		final String enumClsName = value.getClass().getName();
		dos.writeShort(enumClsName.length());
		dos.write(enumClsName.getBytes());
		final String enumName = value.name();
		dos.writeShort(enumName.length());
		dos.write(enumName.getBytes());
	}

	@Override
	void writeArray(final DataOutput dos, final Object array) throws IOException {

		final int arrayLength = Array.getLength(array);
		// Write class name.
		final String className = array.getClass().getComponentType().getName();
		dos.writeShort(className.length());
		dos.write(className.getBytes());
		String itemName;
		for (int i = 0; i < arrayLength; i++) {
			try {
				itemName = ((Enum<?>) Array.get(array, i)).name();
				// Write item name.
				dos.writeShort(itemName.length());
				dos.write(itemName.getBytes());
			} catch (ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
				// Ignore it.
			}
		}
	}
}